﻿/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Reflection;
using Metalama.Framework.Aspects;
using Servicecomb.Saga.Omega.Abstractions.Context;
using Servicecomb.Saga.Omega.Abstractions.Logging;
using Servicecomb.Saga.Omega.Abstractions.Serializing;
using ServiceLocator = Servicecomb.Saga.Omega.Abstractions.Transaction.Extensions.ServiceLocator;

namespace Servicecomb.Saga.Omega.Abstractions.Transaction
{
    [AttributeUsage(AttributeTargets.Method)]
    public class CompensableAttribute : OverrideMethodAspect
    {
        public int Retries { get; set; }
        public string CompensationMethod { get; set; }
        public int RetryDelayInMilliseconds { get; set; }
        public int Timeout { get; set; }

        // 使用动态类型避免编译时类型检查
        /*private dynamic GetService(Type type)
        {
            return ServiceLocator.Current.GetInstance(type);
        }*/

        public override dynamic? OverrideMethod()
        {
            // 获取服务实例
            OmegaContext _omegaContext = (OmegaContext)ServiceLocator.Current.GetInstance(typeof(OmegaContext));
            IEventAwareInterceptor _compensableInterceptor = (IEventAwareInterceptor)ServiceLocator.Current.GetInstance(typeof(IEventAwareInterceptor));
            IRecoveryPolicy _recoveryPolicy = (IRecoveryPolicy)ServiceLocator.Current.GetInstance(typeof(IRecoveryPolicy));
            CompensationContext _compensationContext =
                (CompensationContext)ServiceLocator.Current.GetInstance(typeof(CompensationContext));
            IMessageSerializer _messageFormat = (IMessageSerializer)ServiceLocator.Current.GetInstance(typeof(IMessageSerializer));
            var logger = LogManager.GetLogger(typeof(CompensableAttribute));

            string parentTxId = _omegaContext.GetGlobalTxId();

            // 相当于原来的 OnEntry
            var type = meta.Target.Type.ToType();
            var compensationMethodInfo = type.GetMethod(CompensationMethod, BindingFlags.Instance | BindingFlags.NonPublic);

            // 使用动态调用
            // 修复：使用正确的 API 获取实例和参数
            // 获取目标实例（对于实例方法）
           /* object targetInstance = meta.Target.Method.IsStatic ? null : meta.Target.Instance;

            // 获取参数值
            object[] parameterValues = new object[meta.Target.Parameters.Count];
            for (int i = 0; i < meta.Target.Parameters.Count; i++)
            {
                parameterValues[i] = meta.Target.Parameters[i].Value;
            }*/
            _compensationContext.AddCompensationContext(compensationMethodInfo, type, meta.This);

            _omegaContext.NewLocalTxId();
            var paramBytes = _messageFormat.Serialize(meta.Target.Parameters.ToValueArray());

            logger.Debug($"Initialized context {_omegaContext} before execution of method {meta.Target.Method.Name}");
            _recoveryPolicy.BeforeApply(_compensableInterceptor, _omegaContext, parentTxId, Retries, Timeout, CompensationMethod, paramBytes);

            try
            {
                // 执行原始方法
                var result = meta.Proceed();

                // 相当于原来的 OnExit
                _recoveryPolicy.AfterApply(_compensableInterceptor, parentTxId, CompensationMethod);
                logger.Debug($"Transaction with context {_omegaContext} has finished.");

                return result;
            }
            catch (Exception exception)
            {
                // 相当于原来的 OnException
                logger.Error($"Transaction {_omegaContext.GetGlobalTxId()} failed.", exception);
                _recoveryPolicy.ErrorApply(_compensableInterceptor, parentTxId, CompensationMethod, exception);
                throw;
            }
        }

        // 可选：使用构造函数参数设置属性
        public CompensableAttribute(string compensationMethod, int retryDelayInMilliseconds = 0, int timeout = 0, int retries = 0)
        {
            CompensationMethod = compensationMethod;
            RetryDelayInMilliseconds = retryDelayInMilliseconds;
            Timeout = timeout;
            Retries = retries;
        }
    }
}
